/**
 * @File Name: parser.c
 * @brief  
 *  协议解析文件
 * @Author : LiWanglin email:lwl510ll@163.com
 * @Version : 1.0
 * @Creat Date : 2023-07-11
 * 
 * @copyright Copyright (c) 2023 LiWanglin
 */

#include "parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_PARSER_TEMP_DATA (20)

parser_st *parser_init(cm_uint16 buf_max_len, err_code *err)
{
    parser_st *parser = (parser_st *)malloc(sizeof(parser_st));
    if(NULL == parser) {
        *err = err_malloc_failed;
        return NULL;
    }
    
    memset(parser, 0, sizeof(parser_st));

    parser->q = queue_init(buf_max_len, err);
    if(NULL == parser->q) {
        free(parser);
        parser = NULL;
    }
    
    return parser;
}

parser_st *parser_uninit(parser_st *parser)
{
    if(NULL != parser) {
        if(NULL != parser->q) {
            parser->q = queue_uninit(parser->q);
        }

        free(parser);
        parser = NULL;
    }

    return parser;
}

cm_int16 parser_add_data(parser_st *parser, const cm_uint8 *data, cm_uint16 len)
{
    if(NULL == parser) {
        return err_malloc_failed;
    }

    cm_int16 temp_len = 0;

    err_code err = queue_en(parser->q, data, len);
    if(err < 0) {
        temp_len = err;
    } else {
        temp_len = len;
    }

    return temp_len;
}

protocol_data *parser_deal_data(parser_st *parser, cm_int16 *groups, err_code *err)
{
    *groups = 0;
    *err = err_ok;
    protocol_data *data = NULL;

    if(NULL == parser) {
        *err = err_point_null;
        return data;
    }

    cm_int16 max_data_len = queue_get_max_len(parser->q);
    if(max_data_len <= 0) {
        *err = err_data_len;
        return data;
    }

    cm_uint8 *temp_buf = NULL;
    cm_uint8 temp_data[max_data_len];
    memset(temp_data, 0, max_data_len);

    if(parser->buf_len != 0) {
        memcpy(temp_data, parser->buf, parser->buf_len);
    }

    cm_int16 all_data_len = 0;
    *err = queue_de_all(parser->q, &temp_data[parser->buf_len], &all_data_len);
    all_data_len += parser->buf_len;

    if(*err != err_ok) {
        return data;
    }

    protocol_data temp_protocol_data[MAX_PARSER_TEMP_DATA] = {0};
    parser_status status = PARSER_GET_HEADER;

    cm_int16 header_pos = -1;
    cm_int16 data_len = -1;
    cm_uint16 cmd = -1;
    cm_uint16 seq = -1;
    cm_uint16 crc1 = 0;
    cm_uint16 crc2 = 0;
    cm_int16 leave = 0;

    do {
        switch (status) {
            case PARSER_GET_HEADER:
                for(int i=0; i<all_data_len-1; i++) {
                    if((temp_data[i] == PROTOCOL_HEADER1) && (temp_data[i+1] == PROTOCOL_HEADER2)) {
                        header_pos = i;
                        break;
                    }
                }
                status = (header_pos == -1) ? PARSER_FINISH_FAILED : PARSER_GET_LEN;
                break;

            case PARSER_GET_LEN:
                /* 检查剩余数据长度是否足够 */
                leave = all_data_len - header_pos;
                if(leave < 10) {
                    *err = err_len_not_enough;
                    status = PARSER_FINISH_FAILED;
                } else {
                    /* 获取长度 */
                    data_len = (temp_data[header_pos+2] << 8) | temp_data[header_pos+3];
                    if(data_len > leave) {
                        *err = err_len_not_enough;
                        status = PARSER_FINISH_FAILED;
                    } else {
                        parser->buf_len = 0;
                        status = PARSER_GET_CHECKSUM;
                    }
                }

                if(*err == err_len_not_enough) {
                    memcpy(parser->buf, &temp_data[header_pos], leave);
                    parser->buf_len = leave;
                }
                break;

            case PARSER_GET_CHECKSUM:
                /* 获取校验码1 */
                crc1 = temp_data[header_pos+data_len-2];
                if(crc1 != CRC_NUM1) {
                    *err = err_crc;
                    status = PARSER_FINISH_FAILED;
                } else {
                    /* 检验校验码2 */
                    crc2 = temp_data[header_pos+data_len-1];
                    if(crc2 != check_code_calculation(&temp_data[header_pos], data_len-2)) {
                        *err = err_crc;
                        status = PARSER_FINISH_FAILED;
                    } else {
                        status = PARSER_GET_SERIAL_NUM;
                    }
                }
                break;

            case PARSER_GET_SERIAL_NUM:
                /* 获取序列号 */
                seq = (temp_data[header_pos+4] << 8) | temp_data[header_pos+5];
                status = PARSER_GET_CMD_NUM;
                break;

            case PARSER_GET_CMD_NUM:
                /* 获取命令 */
                cmd = (temp_data[header_pos+6] << 8) | temp_data[header_pos+7];
                status = PARSER_GET_DATA;
                break;
            
            case PARSER_GET_DATA:
                temp_buf = (cm_uint8 *)malloc(data_len);
                if(NULL == temp_buf) {
                    *err = err_malloc_failed;
                    status = PARSER_FINISH_FAILED;
                } else {
                    memcpy(temp_buf, &temp_data[header_pos+6], data_len-6);
                    status = PARSER_FINISH_SUCCESS;
                }
                break;

            case PARSER_FINISH_SUCCESS:
                temp_protocol_data[*groups].data_len  = data_len;
                temp_protocol_data[*groups].serial_num = seq;
                temp_protocol_data[*groups].cmd_num    = cmd;
                temp_protocol_data[*groups].checksum[0] = CRC_NUM1;
                temp_protocol_data[*groups].checksum[1] = crc2;
                temp_protocol_data[*groups].header[0] = PROTOCOL_HEADER1;
                temp_protocol_data[*groups].header[1] = PROTOCOL_HEADER2;
                temp_protocol_data[*groups].data = temp_buf;
                (*groups)++;
                if(*groups == MAX_PARSER_TEMP_DATA) {
                    break;
                }

                memcpy(temp_data, &temp_data[data_len], all_data_len-data_len);
                all_data_len -= data_len;
                if(all_data_len > 0) {
                    status = PARSER_GET_HEADER;
                } else {
                    status = PARSER_FINISH_FAILED;
                }
                break;

            default:
                break;
        }
    } while (status != PARSER_FINISH_FAILED);
    

    if(*groups > 0) {
        data = (protocol_data *)malloc(sizeof(protocol_data)*(*groups));
        if(NULL == data) {
            *err = err_malloc_failed;
        } else {
            memcpy(data, temp_protocol_data, sizeof(protocol_data)*(*groups));
        }
    }

    return data;
}

err_code parser_clean_data(parser_st *parser)
{
    if(NULL == parser) {
        return err_point_null;
    }

    queue_clear(parser->q);
}

